import java.util.ArrayList;


interface IGet {
    int Get(MonthlyRecords record);
}

/*
* Класс, аккумулирующий записи и отвечающий за обработку и
*   сопоставление данных по требованию из Usersitter
*/
public class YearlyRecords {
    //Записи, агрегированные из файлов m.*.csv
    private final MonthlyRecords[] monthlyRecords = new MonthlyRecords[12];

    //Записи, агрегированные из файлов y.*.csv в формате Tuple с
    //  вызванными им издержками
    private final ArrayList<Tuple>[] yearlyRecords = new ArrayList[12];
    private final String[] template = new String[]{"Integer","Boolean"};

    private final String[] monthNames = {"Январь","Февраль","Март","Апрель",
    "Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"};

    private void pushYearlyRecord(Integer month, Tuple tuple) {
        if (yearlyRecords[month] == null) {
            yearlyRecords[month] = new ArrayList<>();
        }
        yearlyRecords[month].add(tuple);
    }

    private void touchMonthRecord(int index) {
        if (monthlyRecords[index] == null) {
            monthlyRecords[index] = new MonthlyRecords();
        }
    }

    //Суммирует поля по int-геттеру
    private int recordsSum(IGet argument) {
        int sum = 0;
        for (int i = 0; i < monthlyRecords.length; ++i) {
            touchMonthRecord(i);
            sum += argument.Get(monthlyRecords[i]);
        }
        return sum;
    }
    private String getAverage(boolean isExpense) {
        double ret = recordsSum((MonthlyRecords rec) -> rec.getSum(isExpense));
        ret /= 12;
        return String.format("%.2f", ret);
    }
    //Добавляет запись в yearlyRecords, распаковывая один Tuple и создавая другой
    public void addYearlyRecord(Tuple tuple) {
        Object[] record;
        try {
            record = tuple.unpack(new String[]{"Integer","Integer", "Boolean"});
        } catch (Exception exception) {
            System.err.println(exception.getMessage());
            return;
        }
        Tuple add = new Tuple(template);
        add.set(0, (Integer) record[1]);
        add.set(1, (Boolean) record[2]);
        int month = ((Integer) record[0]) - 1;
        pushYearlyRecord(month, add);
    }
    public void AddYearlyList(ArrayList<Tuple> tuples) {
        for (Tuple tuple: tuples){
            addYearlyRecord(tuple);
        }
    }
    public void addMonthlyRecord(int numMonth, Tuple tuple) {
        touchMonthRecord(numMonth);
        monthlyRecords[numMonth].addRecord(tuple);
    }
    public void addMonthlyList(Pair<Integer, ArrayList<Tuple>> list) {
        for (Tuple tuple : list.second)
        {
            final int numMonth;
            numMonth = list.first;
            addMonthlyRecord(numMonth, tuple);
        }
    }
    //Сопоставляет yearlyRecords и monthlyRecords по логике из MonthlyRecords
    public String compareData() {
        StringBuilder ret = new StringBuilder();
        for (int i = 0; i < monthlyRecords.length; ++i) {
            if (monthlyRecords[i] == null || yearlyRecords[i] == null) {
                ret.append(String.format("Данных за %8s нет%n", monthNames[i]));
                continue;
            }
            String is_equal;
            is_equal = monthlyRecords[i].compare(yearlyRecords[i]);
            ret.append(String.format("%8s: %s%n", monthNames[i], is_equal));
        }
        return ret.toString();
    }
    //Собирает данные по всем месяцам
    public String getMonthlyData() {
        StringBuilder ret = new StringBuilder();
        for (int i = 0; i < monthlyRecords.length; ++i) {
            if (monthlyRecords[i] == null) {
                ret.append(String.format("%8s - нет данных%n", monthNames[i]));
                continue;
            }
            ret.append(String.format("%8s:%n%s", monthNames[i], monthlyRecords[i].getStatistics()));
        }
        return ret.toString();
    }
    //Выводит данные по году
    public String getYearlyData() {
        StringBuilder ret = new StringBuilder();
        for (int i = 0; i < monthlyRecords.length; ++i) {
            if (monthlyRecords[i] == null) {
                ret.append(String.format("%8s - нет данных%n", monthNames[i]));
                continue;
            }
            ret.append(String.format("%8s:%n", monthNames[i]));
            ret.append(String.format("  Доход: %9s у.е.%n", monthlyRecords[i].getIncome()));
        }
        ret.append(String.format("  Средняя прибыль за год: %6s у.е.%n", getAverage(false)));
        ret.append(String.format("  Средние расходы за год: %6s у.е.%n", getAverage(true)));

        return ret.toString();
    }
}
